package utils

/***
  fifo queue
  线程安全
*/

import (
	"fmt"
	"sync"
)

type MemBlockSyncList struct {
	size     int
	max_size int
	memlst   *MemBlockPool
	lock     *sync.RWMutex
	dlist    *DLinklist
}

func NewMemBlockSyncList(block_size uint16) *MemBlockSyncList {
	rval := &MemBlockSyncList{
		max_size: 0,
		lock:     new(sync.RWMutex),
		dlist:    NewDlinklist(),
	}
	rval.memlst = NewMemBlockPool(block_size)
	return rval
}

func NewMemBlockSyncListEx(pool *MemBlockPool) *MemBlockSyncList {
	rval := &MemBlockSyncList{
		max_size: 0,
		lock:     new(sync.RWMutex),
		dlist:    NewDlinklist(),
	}
	rval.memlst = pool
	return rval
}

func (this *MemBlockSyncList) Size() int {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return this.size
}

func (this *MemBlockSyncList) CacheInfo() string {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return fmt.Sprintf("%d, %d(B)", this.dlist.cnt, this.size)
}

func (this *MemBlockSyncList) ConfigMaxSize(v int) {
	if v <= 1024 || v > 1024*1024*10 {
		v = 1024 * 10
	}
	this.max_size = v

}

func (this *MemBlockSyncList) Close() {
	this.memlst = nil
}

func (this *MemBlockSyncList) Count() int32 {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return this.dlist.cnt
}

func (this *MemBlockSyncList) Reset() {
	this.lock.Lock()
	defer this.lock.Unlock()
	for {
		node := this.dlist.RemoveFirst()
		if node != nil {
			if node.Value != nil {
				node.Value.(*MemBlock).Release2Pool()
			}
			node.Value = nil
			node.release2Pool() // 归还node
		}
		if node == nil {
			break
		}
	}
	this.size = 0
}

func (this *MemBlockSyncList) innerGetLast() *MemBlock {
	v := this.dlist.SeekLast()
	if v == nil {
		return nil
	}
	return v.Value.(*MemBlock)
}

func (this *MemBlockSyncList) PopMemBlock() (rval *MemBlock) {
	this.lock.Lock()
	defer this.lock.Unlock()
	node := this.dlist.RemoveFirst()
	if node != nil {
		if node.Value != nil {
			rval = node.Value.(*MemBlock)
			this.size -= int(rval.write_idx)
		}
		node.Value = nil
		node.release2Pool() // 归还node
	}
	return
}

func (this *MemBlockSyncList) PopCopyBuf() (rval []byte) {
	this.lock.Lock()
	defer this.lock.Unlock()
	node := this.dlist.RemoveFirst()
	if node != nil {
		if node.Value != nil {
			blk := node.Value.(*MemBlock)
			// copy
			tmp := blk.GetBytes()
			rval = make([]byte, len(tmp))
			copy(rval, tmp)
			blk.Release2Pool()

			this.size -= len(rval)
		}
		node.Value = nil
		node.release2Pool() // 归还node
	}
	return
}

func (this *MemBlockSyncList) GetBytes() []byte {
	var sb BytesBuilder
	this.lock.RLock()
	defer this.lock.RUnlock()
	this.dlist.Range(func(val interface{}) bool {
		blk := val.(*MemBlock)
		sb.Write(blk.GetBytes())
		return true
	})
	return sb.Bytes()
}

func (this *MemBlockSyncList) Write(buf []byte) (n int, err error) {
	this.lock.Lock()
	defer this.lock.Unlock()
	last := this.innerGetLast()
	n = 0
	l0 := len(buf)
	if this.max_size > 0 && this.size+l0 > this.max_size {
		err = fmt.Errorf("超过最大允许写入大小[%d], 写入失败!", this.max_size)
		return
	}

	if last != nil {
		n0, _ := last.Write(buf)
		n += n0
	}

	for {
		if n == l0 {
			break
		}

		block := this.memlst.GetBlock()
		n0, _ := block.Write(buf[n:])
		n += n0
		node := NewDlinknodeFromPool()
		node.Value = block
		this.dlist.Append(node)
	}

	this.size += n
	return
}
